package com.xfcy.blog.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xfcy.blog.common.R;
import com.xfcy.blog.common.constant.Constant;
import com.xfcy.blog.common.constant.RedisConstant;
import com.xfcy.blog.common.constant.SqlConstant;
import com.xfcy.blog.dto.CommentDTO;
import com.xfcy.blog.entity.UserAuth;
import com.xfcy.blog.exception.CustomerException;
import com.xfcy.blog.mapper.CommentMapper;
import com.xfcy.blog.entity.Comment;
import com.xfcy.blog.mapper.UserAuthMapper;
import com.xfcy.blog.service.CommentService;
import com.xfcy.blog.utils.BeanCopyUtil;
import com.xfcy.blog.utils.HtmlUtils;
import com.xfcy.blog.vo.CommentVO;
import com.xfcy.blog.vo.ReplyCountVO;
import com.xfcy.blog.vo.ReplyVO;
import com.xfcy.blog.vo.SystemCommentVO;
import io.swagger.models.auth.In;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 评论表(Comment)表服务实现类
 *
 * @author 晓风残月Lx
 * @since 2023-04-09 11:03:05
 */
@Service("commentService")
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Resource
    private UserAuthMapper userAuthMapper;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 后端分页查询
     * @param pageNo
     * @param pageSize
     * @param keywords
     * @param isDeleted
     * @return
     */
    @Override
    public R listComment(Integer pageNo, Integer pageSize, String keywords, Integer isDeleted) {
        Page<SystemCommentVO> dtoPage = baseMapper.listComment(new Page<>(pageNo, pageSize), keywords, isDeleted);
        return R.success(dtoPage);
    }

    /**
     * 批量删除评论
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R deleteBatchComment(List<Long> ids) {
        baseMapper.deleteBatchComment(ids);
        return R.success();
    }









    // web端方法
    /**
     * 查看评论 分页
     *
     * @param pageNo
     * @param pageSize
     * @param articleId
     * @return
     */
    @Override
    public R getComments(Integer pageNo, Integer pageSize, Long articleId, Integer index) {

        // 查询父文章评论数
        Integer commentCount = baseMapper.selectCount(new LambdaQueryWrapper<Comment>()
                .eq(Objects.nonNull(articleId), Comment::getArticleId, articleId)
                .isNull(Objects.isNull(articleId), Comment::getArticleId)
                .eq(Comment::getParentId, Constant.ZERO));

        if (commentCount == Constant.ZERO) {
            return R.success();
        }

        Page<Comment> commentPage = null;

        if (index == Constant.ONE) {
            commentPage = baseMapper.selectPage(new Page<>(pageNo, pageSize), new LambdaQueryWrapper<Comment>()
                    .eq(Comment::getArticleId, articleId)
                    .eq(Comment::getParentId, Constant.ZERO)
                    .orderByDesc(Comment::getCreateTime));
        } else if (index == Constant.TWO){
            commentPage = baseMapper.selectPage(new Page<>(pageNo, pageSize), new LambdaQueryWrapper<Comment>()
                    .eq(Comment::getArticleId, articleId)
                    .eq(Comment::getParentId, Constant.ZERO)
                    .orderByDesc(Comment::getLikeCount));
        } else {
            return R.error("系统出现了问题，请重试！");
        }

        List<Comment> comments = commentPage.getRecords();

        if (CollectionUtil.isEmpty(comments)) {
            return R.success();
        }

        // 查询每一个父评论下的子评论
        List<CommentVO> commentVOList = new ArrayList<>();
        List<ReplyVO> replyVOList;

        // 根据评论集合查询子评论数据集合
        for (Comment comment : comments) {
            // 查询出父评论的用户信息
            UserAuth userAuth = userAuthMapper.getByUserId(comment.getUserId());

            // 查询父评论点赞数
            Object o = redisTemplate.opsForHash().get(RedisConstant.COMMENT_LIKE_COUNT + articleId, comment.getId().toString());

            // 查询所有子评论和子点赞数
            replyVOList = baseMapper.listReplies(comment.getId());

            // 查询子评论点赞数
            replyVOList = replyVOList.stream().map(item -> {
                Object childrenLikeCount = redisTemplate.opsForHash().get(RedisConstant.COMMENT_LIKE_COUNT + articleId, item.getId().toString());
                if (Objects.nonNull(childrenLikeCount) && (Integer) childrenLikeCount >= 0) {
                    item.setLikeCount((Integer) childrenLikeCount);
                }
                return item;
            }).collect(Collectors.toList());

            // 查询子评论数
            ReplyCountVO replyCountVO = baseMapper.listReplyCountByCommentId(comment.getId());

            CommentVO commentVO = new CommentVO();
            commentVO.setId(comment.getId());
            commentVO.setUserId(comment.getUserId());
            commentVO.setCommentContent(comment.getContent());
            commentVO.setCreateTime(comment.getCreateTime());
            commentVO.setAvatar(userAuth.getAvatar());
            commentVO.setNickname(userAuth.getNickname());
            commentVO.setReplyVOList(replyVOList);

            commentVO.setLikeCount(Objects.isNull(o) ? comment.getLikeCount() : (Integer) o);

            commentVO.setReplyCount(replyCountVO == null ? 0 : replyCountVO.getReplyCount());

            commentVOList.add(commentVO);
        }

        Map<String, Object> map = new HashMap<>();
        map.put("commentCount", commentCount);
        map.put("commentVOList", commentVOList);
        return R.success(map);
    }

    /**
     * 查看评论回复 分页
     *
     * @param pageNo
     * @param pageSize
     * @param commentId
     * @return
     */
    @Override
    public R repliesByComId(Integer pageNo, Integer pageSize, Integer commentId) {
        Page<Comment> page = baseMapper.selectPage(new Page<>(pageNo, pageSize), new QueryWrapper<Comment>()
                .eq(SqlConstant.PARENT_ID, commentId)
                .orderByDesc(SqlConstant.CREATE_TIME));

        List<ReplyVO> result = new ArrayList<>();

        for (Comment record : page.getRecords()) {
            UserAuth userAuth = userAuthMapper.getByUserId(record.getUserId());
            UserAuth replyUserAuth = userAuthMapper.getByUserId(record.getReplyUserId());

            Object o = redisTemplate.opsForHash().get(RedisConstant.COMMENT_LIKE_COUNT + record.getArticleId(), record.getId());

            ReplyVO replyVO = new ReplyVO();

            replyVO.setId(record.getId());
            replyVO.setAvatar(userAuth.getAvatar());
            replyVO.setNickname(userAuth.getNickname());
            replyVO.setUserId(userAuth.getId());
            replyVO.setContent(record.getContent());
            replyVO.setReplyUserId(replyUserAuth.getId());
            replyVO.setReplyNickname(replyUserAuth.getNickname());
            replyVO.setParentId(commentId);
            replyVO.setLikeCount(Objects.isNull(o) ? record.getLikeCount() : (Integer) o);
            replyVO.setCreateTime(record.getCreateTime());

            result.add(replyVO);
        }

        return R.success(result);
    }

    /**
     * 添加评论
     *
     * @param commentDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addComment(CommentDTO commentDTO) {
        // 过滤标签
        commentDTO.setCommentContent(HtmlUtils.deleteTag(commentDTO.getCommentContent()));

        Comment comment = new Comment();
        comment.setReplyUserId(commentDTO.getReplyUserId() == null ? Constant.ZERO : commentDTO.getReplyUserId());
        comment.setParentId(commentDTO.getParentId() == null ? 0 : commentDTO.getParentId());
        comment.setContent(commentDTO.getCommentContent());
        comment.setArticleId(commentDTO.getArticleId());
        comment.setUserId(commentDTO.getUserId() == null ? StpUtil.getLoginIdAsInt() : commentDTO.getUserId());
        comment.setReplyUserId(commentDTO.getReplyUserId() == null ? 0 : commentDTO.getReplyUserId());

        int rows = baseMapper.insert(comment);

        return rows > 0 ? R.success() : R.error("评论失败");

    }

    /**
     * 评论点赞或取消评论点赞
     *
     * @param commentId
     * @return
     */
    @Override
    public R likeComment(Integer commentId, Long articleId) {
        // 用户id
        Long loginId = StpUtil.getLoginIdAsLong();
        // 文章下所有评论的点赞量的key
        String articleIdCommentLikeCount = RedisConstant.COMMENT_LIKE_COUNT + articleId;
        // 用户点赞过的评论的key
        String userCommentLiked = RedisConstant.USER_COMMENT_LIKED + loginId;

        String script = "if redis.call('SISMEMBER', KEYS[1], ARGV[1]) == 1 then " +
                "redis.call('SREM', KEYS[1], ARGV[1]) " +
                "redis.call('HINCRBY', KEYS[2], KEYS[3], ARGV[2]) " +
                "return 0 " +
                "elseif redis.call('SISMEMBER', KEYS[1], ARGV[1]) == 0 then " +
                "redis.call('SADD', KEYS[1], ARGV[1]) " +
                "redis.call('HINCRBY', KEYS[2], KEYS[3], ARGV[3]) " +
                "return 1 " +
                "else " +
                "return -1 " +
                "end";

        Long execute = (Long) redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(userCommentLiked, articleIdCommentLikeCount, commentId.toString()), commentId, Constant.LONG_NEGATIVE_ONE, Constant.LONG_ONE);
        if (execute == Constant.LONG_ZERO) {
            return R.success("取消点赞成功！");
        } else if (execute == Constant.LONG_ONE) {
            return R.success("点赞成功！");
        } else {
            return R.error();
        }

    }

    /**
     * 删除评论逻辑删除
     * @param commentId
     * @return
     */
    @Override
    public R deleteComment(Integer commentId) {
        int i = baseMapper.deleteById(commentId);
        return i > 0 ?  R.success("删除评论成功！") : R.error("删除评论失败");
    }


}


